Spring Security Note-5
使用Spring Security开发基于表单的认证
介绍Spring Security的基本原理和核心概念;
如何利用Spring Security提供的开箱即用的功能快速开发基于用户名密码的登录;
如何扩展Spring Security的默认实现来满足个性化的需求;
深入了解Spring Security的源码实现;
如何向Spring Security中加入完全自定义的登录方式;
Spring Security核心功能:
认证(你是谁)、授权(你能干什么)、攻击防护(防止伪造身份)
Spring Security基本原理
当我们将前面学习中,关闭的Spring Security身份验证,重新打开时,进行默认身份验证的测试;
1 | # spring-security |
当访问http://localhost:8060/user时候,通过user,Using default security password的方式,进行访问;
在没有进行任何配置的时候,Spring Security默认对所有请求和访问都进行了身份认证的拦截;
接下来,我们通过登录页面 & 表单认证的方式,进行身份的认证;
1 |
|
讲解:
REST API(服务中的Controller);
Spring Security最核心的东西叫:Spring Security过滤器链;
所有的请求,都会经过过滤器链,响应也一致;
最核心的过滤器:Basic Authentication Filter
、UsernamePassword Authentication Filter
等等;
这些过滤器作用在于检验你的请求中,是否存在可以通过过滤器需要认证的信息;
请求的过滤器经过认证后,在过滤器链最后一环叫:FilterSecurity Interceptor
;
它将通过我们的配置判断是否身份认证成功;
虽然进过身份认证,但是不存在权限,在FilterSecurity Interceptor
之前,存在一个Exception Translation Filter
去返回响应存在的异常,引导登录或授权等;
测试
在以上提到的过滤器和自定义的Controller中,通过打断点,Debugger的方式,进行一次源码的解析;
1.当访问服务http://localhost:8060/user 时,将进入到FilterSecurity Interceptor
当中进行判断是否可以进行服务的请求,但是用于在配置当中,我们声明所有的请求都需要身份验证,此时将抛出异常;
2.抛出的异常
org.springframework.security.access.AccessDeniedException: Access is denied
将由Exception Translation Filter
捕获,并且将重定向到一个登录的页面当中;
3.重定向到http://localhost:8060/login 之后,进行登录的请求操作;
4.此时将访问到UsernamePassword Authentication Filter
进行认证;
5.登录请求之后,将再次跳转到FilterSecurity Interceptor
进行请求,在这之间有一个http://localhost:8060/user的再次请求;
6.此时没有报异常,将成功请求;
自定义用户认证逻辑
处理用户信息获取逻辑(数据库)
用户信息获取的逻辑,被Spring Security封装在了UserDeatialService
当中,里面只有一个方法;
1 | public interface UserDetailsService { |
1 |
|
此时可以根据实现的UserDetailService
进行自定义的用户认证,内容包括用户名,密码和权限;
处理用户校验逻辑(验证)
密码是否匹配;用户是否冻结;密码是否过期等等;
在具体返回的类型当中UserDetails
存在四个boolean的方法,我们可以通过重新方法的方式,自定义不同的校验逻辑;
1 | public interface UserDetails extends Serializable { |
如果是自定义的用户类型,不管是Mybatis还是JPA等数据库获取数据的范式,只需要将自定义的用户实例实现UserDetails
即可;
处理密码加密和解密
在数据库中取出的密码以及存入数据库中的密码,是需要通过加密以及解密的过程;
在Spring Security中已有这样的接口,可以具体实现加密和解密,叫做PasswordEncoder
;
1 | public interface PasswordEncoder { |
配置一个PasswordEncoder
1 |
|
1 |
|
尝试多次登录,我们发现,默认的123456密码,两次加密结果不一致?
这是Spring Security的强大之处,随机生成一个salt值,与每次的密码进行加密和解密;
个性化用户认证流程
自定义登录页面
1 |
|
其中遇到的问题包括
1.需要配置无须授权的页面,不然在.anyRequest()
的配置条件下,自定义的登录页面,也属于请求,将会死循环的页面的重定向;
2.登录页面表单的提交方式使用/authentication/form
,需要进行配置,以告诉Spring Secure,需要通过UsernamePassword Authentication Filter
进行表单认证;
3.无效的CSRF Token:Spring Security默认提供跨站请求伪造的防护机制,暂时关闭;
1 |
|
1 |
|
自定义登录成功处理
实现接口AuthenticationSuccessHandler
即可
1 | "imoocAuthenticationSuccessHandler") ( |
1 |
|
成功登录后,返回的authentication
内容包括,根据登录方式不同,包含的信息也是不同的;
自定义登录失败处理
1 | "imoocAuthenticationFailHandler") ( |
1 |
|
重构
重构代码,使模块同时支持同步和异步的请求,是跳转还是返回JSON;
1 | public class BrowserProperties { |
1 | public enum LoginType { |
1 | "imoocAuthenticationSuccessHandler") ( |
1 | "imoocAuthenticationFailHandler") ( |
根据用户的不同配置,就可以定义具体的返回是重定向页面还是返回JSON格式的数据;
附言
在Core项目中,对配置进行封装;
1 |
|
1 | "imooc.security") (prefix = |
1 | public class BrowserProperties { |